#include "Oculus_KartVRFrameListener.h"

Oculus_KartVRFrameListener::Oculus_KartVRFrameListener(
	SceneManager *sceneMgr,
	RenderWindow *win,
	Vector3 &gravityVector,
	AxisAlignedBox &bounds,
	bool bufferedKeys,
	bool bufferedMouse,
	bool bufferedJoy) : mSceneMgr(sceneMgr), mTranslateVector(Vector3::ZERO), mCurrentSpeed(0), mWindow(win), mStatsOn(false), mNumScreenShots(0),
	mMoveScale(0.0f), mRotScale(0.0f), mTimeUntilNextToggle(0), mFiltering(TFO_BILINEAR), mAniso(1), mSceneDetailIndex(0), mMoveSpeed(0.002f),
	mRotateSpeed(36), mDebugOverlay(0),	mInputManager(0), mMouse(0), mKeyboard(0), mJoy(0)
{
	mNumLaps = 5;
	restartRace = false;
	changeGameState(LOADING);
	mTimingGates.push_back(TimingGate(Vector3(-11.5f, 0, 169.4f), 150.0f));
	mTimingGates.push_back(TimingGate(Vector3(234.4f, 0, 400.0f), 150.0f));
	mTimingGates.push_back(TimingGate(Vector3(617.4f, 0, -189.0f), 150.0f));
#pragma region Input_region
	LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
	OIS::ParamList pl;
	size_t windowHnd = 0;
	std::ostringstream windowHndStr;
	win->getCustomAttribute("WINDOW", &windowHnd);
	windowHndStr << windowHnd;
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
	mInputManager = OIS::InputManager::createInputSystem( pl );

	//Create all devices (We only catch joystick exceptions here, as, most people have Key/Mouse)
	mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, bufferedKeys ));
	mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, bufferedMouse ));
	try {
		mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject( OIS::OISJoyStick, bufferedJoy ));
		mJoy->setEventCallback(this);
	}
	catch(...) {
		mJoy = 0;
	}

	//Set initial mouse clipping size
	windowResized(mWindow);
	freeCam = false;
	mKeyboard->copyKeyStates(mPrevKeys);
#pragma endregion Input_region

	//mSceneMgr = sceneMgr;
	mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
	mDebugOverlay->hide();
	showDebugOverlay(mStatsOn);

	//Register as a Window listener
	WindowEventUtilities::addWindowEventListener(mWindow, this);

#pragma region Physics_region
	mNumEntitiesInstanced = 0; // how many shapes are created
	// Start Bullet
	mWorld = new OgreBulletDynamics::DynamicsWorld(mSceneMgr, bounds, gravityVector);

	// add Debug info display tool
	debugDrawer = new OgreBulletCollisions::DebugDrawer();
	debugDrawer->setDrawWireframe(false);	// enable it if you want to see the Bullet containers

	mWorld->setDebugDrawer(debugDrawer);
	mWorld->setShowDebugShapes(false);		// enable it if you want to see the Bullet containers

	mTrackRoad = mSceneMgr->createEntity("trackRoad", "MyKartTrack_road.mesh");
	mTrackRoadNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("TrackRoadNode");
	mTrackRoadNode->attachObject(mTrackRoad);
	mTrackRoad->setCastShadows(true);
	OgreBulletCollisions::StaticMeshToShapeConverter *trimeshConverter = new OgreBulletCollisions::StaticMeshToShapeConverter(mTrackRoad);
	OgreBulletCollisions::TriangleMeshCollisionShape *sceneTriMeshShape = trimeshConverter->createTrimesh();
	delete trimeshConverter;
	OgreBulletDynamics::RigidBody *trackBody = new OgreBulletDynamics::RigidBody("TrackRoadBody", mWorld);
	trackBody->setStaticShape(sceneTriMeshShape, 0.1f, 1.0f, 0.5f, Vector3::ZERO, Quaternion::IDENTITY);

	mTrackGrass = mSceneMgr->createEntity("trackGrass", "MyKartTrack_grass.mesh");
	mTrackGrassNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("TrackGrassNode");
	mTrackGrassNode->attachObject(mTrackGrass);
	mTrackGrass->setCastShadows(true);
	OgreBulletCollisions::StaticMeshToShapeConverter *trimeshConverter2 = new OgreBulletCollisions::StaticMeshToShapeConverter(mTrackGrass);
	OgreBulletCollisions::TriangleMeshCollisionShape *sceneTriMeshShape2 = trimeshConverter2->createTrimesh();
	delete trimeshConverter2;
	OgreBulletDynamics::RigidBody *trackBody2 = new OgreBulletDynamics::RigidBody("TrackGrassBody", mWorld);
	trackBody2->setStaticShape(sceneTriMeshShape2, 0.4f, 0.2f, 0.1f, Vector3::ZERO, Quaternion::IDENTITY);

	mPlayer = new Player(mSceneMgr, mWorld, Vector3(-10.0f,0.9f,0), &mTimingGates, &mRaceTime, false);
#pragma endregion Physics_region

#pragma region Oculus_region
	m_Cameras[0] = mSceneMgr->createCamera("LeftEyeCamera");
	m_Cameras[1] = mSceneMgr->createCamera("RightEyeCamera");

	mORM =  new Oculus_RiftManager();
	mORM->setup();
	SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode("OculusCameraNode", Ogre::Vector3::ZERO);
	node->attachObject(static_cast <SimpleRenderable *> (debugDrawer));

	Ogre::MaterialPtr matLeft = Ogre::MaterialManager::getSingleton().getByName("Ogre/Compositor/Oculus");
	Ogre::MaterialPtr matRight = matLeft->clone("Ogre/Compositor/Oculus/Right");
	Ogre::GpuProgramParametersSharedPtr pParamsLeft = matLeft->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
	Ogre::GpuProgramParametersSharedPtr pParamsRight = matRight->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
	Ogre::Vector4 hmdwarp;
	if(mORM->getStereoConfig())
	{
		hmdwarp = Ogre::Vector4(mORM->getStereoConfig()->GetDistortionK(0),
			mORM->getStereoConfig()->GetDistortionK(1),
			mORM->getStereoConfig()->GetDistortionK(2),
			mORM->getStereoConfig()->GetDistortionK(3));
	}
	else
	{
		hmdwarp = Ogre::Vector4(g_defaultDistortion[0],
			g_defaultDistortion[1],
			g_defaultDistortion[2],
			g_defaultDistortion[3]);
	}
	pParamsLeft->setNamedConstant("HmdWarpParam", hmdwarp);
	pParamsRight->setNamedConstant("HmdWarpParam", hmdwarp);
	pParamsLeft->setNamedConstant("LensCentre", 0.5f+(mORM->getStereoConfig()->GetProjectionCenterOffset()/2.0f));
	pParamsRight->setNamedConstant("LensCentre", 0.5f-(mORM->getStereoConfig()->GetProjectionCenterOffset()/2.0f));

	Ogre::CompositorPtr comp = Ogre::CompositorManager::getSingleton().getByName("OculusRight");
	comp->getTechnique(0)->getOutputTargetPass()->getPass(0)->setMaterialName("Ogre/Compositor/Oculus/Right");

	for(int i=0;i<2;++i)
	{
		node->attachObject(m_Cameras[i]);
		if(mORM->getStereoConfig())
		{
			// Setup cameras.
			m_Cameras[i]->setNearClipDistance(mORM->getStereoConfig()->GetEyeToScreenDistance());
			m_Cameras[i]->setFarClipDistance(g_defaultFarClip);
			m_Cameras[i]->setPosition((i * 2 - 1) * mORM->getStereoConfig()->GetIPD() * 0.5f, 0, 0);
			m_Cameras[i]->setAspectRatio(mORM->getStereoConfig()->GetAspect());
			m_Cameras[i]->setFOVy(Ogre::Radian(mORM->getStereoConfig()->GetYFOVRadians()));

			// Oculus requires offset projection, create a custom projection matrix
			Ogre::Matrix4 proj = Ogre::Matrix4::IDENTITY;
			float temp = mORM->getStereoConfig()->GetProjectionCenterOffset();
			proj.setTrans(Ogre::Vector3(-mORM->getStereoConfig()->GetProjectionCenterOffset() * (2 * i - 1), 0, 0));
			m_Cameras[i]->setCustomProjectionMatrix(true, proj * m_Cameras[i]->getProjectionMatrix());
		}
		else
		{
			m_Cameras[i]->setNearClipDistance(g_defaultNearClip);
			m_Cameras[i]->setFarClipDistance(g_defaultFarClip);
			m_Cameras[i]->setPosition((i*2-1) * g_defaultIPD * 0.5f, 0, 0);
		}
		m_viewports[i] = win->addViewport(m_Cameras[i], i, 0.5f*i, 0, 0.5f, 1.0f);
		m_viewports[i]->setBackgroundColour(g_defaultViewportColour);
		m_compositors[i] = Ogre::CompositorManager::getSingleton().addCompositor(m_viewports[i],i==0?"OculusLeft":"OculusRight");
		m_compositors[i]->setEnabled(true);
	}
#pragma endregion Oculus_region

#pragma region UI_region
	mRaceTime = 0;
	mCountDown = 5000;
	mShowLastLapTime = 5000;
	mBeepCooldown = 980;
	mSilverBack = new Gorilla::Silverback();
	mSilverBack->loadAtlas("dejavu");

	//Race count down panel
	mCountDownPanel = new D3Panel(mSilverBack, mSceneMgr, Vector2(0.585f,0.235f));
	mCountDownPanel->mD3PanelNode->yaw(Degree(180));
	mCountDownPanel->setVisible(false);
	mCountDownCaption = mCountDownPanel->makeCaption(0,0,"");
	mCountDownCaption->width(60);
	mCountDownCaption->align(Gorilla::TextAlign_Centre);

	//Speed panel
	mSpeedPanel = new D3Panel(mSilverBack, mSceneMgr, Vector2(0.91f,0.235f));
	mSpeedPanel->mD3PanelNode->yaw(Degree(180));
	mSpeedPanel->setVisible(true);
	mSpeedCaption = mSpeedPanel->makeCaption(0,0,"");
	mSpeedCaption->width(91);
	mSpeedCaption->align(Gorilla::TextAlign_Centre);

	//Timer panel
	mTimerPanel = new D3Panel(mSilverBack, mSceneMgr, Vector2(0.97f,0.235f));
	mTimerPanel->mD3PanelNode->yaw(Degree(180));
	mTimerPanel->setVisible(true);
	mTimerCaption = mTimerPanel->makeCaption(0,0,"");
	mTimerCaption->width(97);
	mTimerCaption->align(Gorilla::TextAlign_Centre);

	//Position panel
	mPositionPanel = new D3Panel(mSilverBack, mSceneMgr, Vector2(0.55f,0.235f));
	mPositionPanel->mD3PanelNode->yaw(Degree(180));
	mPositionPanel->setVisible(true);
	mPositionCaption = mPositionPanel->makeCaption(0,0,"");
	mPositionCaption->width(55);
	mPositionCaption->align(Gorilla::TextAlign_Left);

	//Lap panel
	mLapPanel = new D3Panel(mSilverBack, mSceneMgr, Vector2(0.4f,0.235f));
	mLapPanel->mD3PanelNode->yaw(Degree(180));
	mLapPanel->setVisible(true);
	mLapCaption = mLapPanel->makeCaption(0,0,"");
	mLapCaption->width(40);
	mLapCaption->align(Gorilla::TextAlign_Right);

	//Race end panel
	mRaceEndPanel = new D3Panel(mSilverBack, mSceneMgr, Vector2(1.9f,0.585f));
	mRaceEndPanel->mD3PanelNode->yaw(Degree(180));
	mRaceEndPanel->setVisible(false);
	mRaceEndFinishCap = mRaceEndPanel->makeCaption(0,0,"Finish!!!");
	mRaceEndFinishCap->width(190);
	mRaceEndFinishCap->align(Gorilla::TextAlign_Centre);
	mRaceEndPosCap = mRaceEndPanel->makeCaption(0,18.0f,"");
	mRaceEndPosCap->width(190);
	mRaceEndPosCap->align(Gorilla::TextAlign_Centre);
	mRaceEndBestLapCap = mRaceEndPanel->makeCaption(0,36.0f,"");
	mRaceEndBestLapCap->width(190);
	mRaceEndBestLapCap->align(Gorilla::TextAlign_Centre);
#pragma endregion UI_region

#pragma region Sound_region
	// setup pointer to sound manager
	mSoundManager = OgreOggSound::OgreOggSoundManager::getSingletonPtr();
	mSoundManager->init();
	mSoundManager->setDistanceModel(AL_EXPONENT_DISTANCE);
	headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,0), Quaternion::IDENTITY);
	headNode->setPosition((m_Cameras[0]->getPosition() + m_Cameras[1]->getPosition()) / 2);
	headNode->setOrientation(m_Cameras[0]->getOrientation());
	headNode->attachObject(mSoundManager->getListener());
	mSoundManager->createSound("BGM", "BGMLoop.ogg", false, true, true);
	mSoundManager->getSound("BGM")->setVolume(1.0f);
	mSoundManager->createSound("Beep", "Beep.ogg", false, false, true, 0 , true);
	mSoundManager->getSound("Beep")->setVolume(0.75f);
	mSoundManager->createSound("FinalBeep", "FinalBeep.ogg", false, false, true, 0 , true);
	mSoundManager->getSound("FinalBeep")->setVolume(1.0f);
	mSoundManager->createSound("Engine_Rev", "engine_rev.ogg", false, true, true);
	mSoundManager->getSound("Engine_Rev")->setVolume(0.25f);
	mSoundManager->getSound("Engine_Rev")->setRolloffFactor(2.0f);
	mSoundManager->getSound("Engine_Rev")->setReferenceDistance(10.0f);
	mSoundManager->getSound("Engine_Rev")->setPitch(0.65f);
	mPlayer->attachSoundtoEngine("Engine_Rev", mSoundManager);
#pragma endregion Sound_region

#pragma region AI_region
	mAI_Waypoints.push_back(Waypoint(Vector3(-29,0,70), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(-97,0,169), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(-165,0,258), 15, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(-194,0,312), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(-202,0,527), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(-186,0,619), 20, 80));
	mAI_Waypoints.push_back(Waypoint(Vector3(-132,0,639), 15, 50));
	mAI_Waypoints.push_back(Waypoint(Vector3(-81,0,593), 40, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(-121,0,464), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(-91,0,420), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(-38,0,390), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(75,0,417), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(133,0,382), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(177,0,320), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(202,0,150), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(282,0,94), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(305,0,121), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(310,0,176), 30, 999)); 
	mAI_Waypoints.push_back(Waypoint(Vector3(320,0,210), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(385,0,247), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(447,0,219), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(527,0,135), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(604,0,-81), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(587,0,-150), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(533,0,-203), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(400,0,-209), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(177,0,-203), 20, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(67,0,-283), 20, 65));
	mAI_Waypoints.push_back(Waypoint(Vector3(29,0,-280), 15, 45));
	mAI_Waypoints.push_back(Waypoint(Vector3(-20,0,-234), 30, 999));
	mAI_Waypoints.push_back(Waypoint(Vector3(2,0,-69), 20, 999));

	float a = -18;
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,-9.0f));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*1-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*1));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*2-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*2));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*3-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*3));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*4-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*4));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*5-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*5));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*6-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*6));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*7-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*7));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*8-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*8));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*9-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*9));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*10-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*10));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*11-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*11));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*12-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*12));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*13-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*13));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*14-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*14));
	mAgentStartPos.push_back(Vector3(0.0f,0.9f,a*15-9));
	mAgentStartPos.push_back(Vector3(-10.0f,0.9f,a*15));
	mAI_Manager = new AI_Manager(mSceneMgr, mWorld, mSoundManager, mAgentStartPos, &mAI_Waypoints, &mTimingGates, &mRaceTime);
#pragma endregion AI_region
}

Oculus_KartVRFrameListener::~Oculus_KartVRFrameListener()
{
	// OgreBullet physic delete - RigidBodies
	std::deque<OgreBulletDynamics::RigidBody *>::iterator itBody = mBodies.begin();
	while (mBodies.end() != itBody)
	{   
		delete *itBody; 
		++itBody;
	}
	// OgreBullet physic delete - Shapes
	std::deque<OgreBulletCollisions::CollisionShape *>::iterator itShape = mShapes.begin();
	while (mShapes.end() != itShape)
	{   
		delete *itShape; 
		++itShape;
	}
	mBodies.clear();
	mShapes.clear();
	delete mWorld->getDebugDrawer();
	mWorld->setDebugDrawer(0);
	delete mWorld;

	delete mSilverBack;

	//Remove ourself as a Window listener
	WindowEventUtilities::removeWindowEventListener(mWindow, this);
	windowClosed(mWindow);
}

void Oculus_KartVRFrameListener::windowResized(RenderWindow *rw)
{
	unsigned int width, height, depth;
	int left, top;
	rw->getMetrics(width, height, depth, left, top);

	const OIS::MouseState &ms = mMouse->getMouseState();
	ms.width = width;
	ms.height = height;
}

void Oculus_KartVRFrameListener::windowClosed(RenderWindow *rw)
{
	//Only close for window that created OIS (the main window in these demos)
	if( rw == mWindow )
	{
		if( mInputManager )
		{
			mInputManager->destroyInputObject( mMouse );
			mInputManager->destroyInputObject( mKeyboard );
			mInputManager->destroyInputObject( mJoy );

			OIS::InputManager::destroyInputSystem(mInputManager);
			mInputManager = 0;
		}
	}
}

bool Oculus_KartVRFrameListener::processUnbufferedKeyInput(const FrameEvent& evt)
{
	Real moveScale = mMoveScale;
	if(mKeyboard->isKeyDown(OIS::KC_LSHIFT))
		moveScale *= 100;

	if(mKeyboard->isKeyDown(OIS::KC_A))
		mTranslateVector.x = -moveScale;	// Move camera left

	if(mKeyboard->isKeyDown(OIS::KC_D))
		mTranslateVector.x = moveScale;	// Move camera RIGHT

	if(mKeyboard->isKeyDown(OIS::KC_W) )
		mTranslateVector.z = -moveScale;	// Move camera forward

	if(mKeyboard->isKeyDown(OIS::KC_S) )
		mTranslateVector.z = moveScale;	// Move camera backward

	if(mKeyboard->isKeyDown(OIS::KC_PGUP))
		mTranslateVector.y = moveScale;	// Move camera up

	if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))
		mTranslateVector.y = -moveScale;	// Move camera down

	if(mKeyboard->isKeyDown(OIS::KC_ESCAPE))
		return false;

	if(mKeyboard->isKeyDown(OIS::KC_F) && mTimeUntilNextToggle <= 0)
	{
		freeCam = !freeCam;
		mTimeUntilNextToggle = 250;
	}

	if(mKeyboard->isKeyDown(OIS::KC_G) && mTimeUntilNextToggle <= 0)
	{
		mStatsOn = !mStatsOn;
		showDebugOverlay(mStatsOn);
		mTimeUntilNextToggle = 250;
	}

	if(mKeyboard->isKeyDown(OIS::KC_T) && mTimeUntilNextToggle <= 0)
	{
		switch(mFiltering)
		{
		case TFO_BILINEAR:
			mFiltering = TFO_TRILINEAR;
			mAniso = 1;
			break;
		case TFO_TRILINEAR:
			mFiltering = TFO_ANISOTROPIC;
			mAniso = 8;
			break;
		case TFO_ANISOTROPIC:
			mFiltering = TFO_BILINEAR;
			mAniso = 1;
			break;
		default: break;
		}
		MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
		MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);

		showDebugOverlay(mStatsOn);
		mTimeUntilNextToggle = 250;
	}

	if(mKeyboard->isKeyDown(OIS::KC_SYSRQ) && mTimeUntilNextToggle <= 0)
	{
		std::ostringstream ss;
		ss << "screenshot_" << ++mNumScreenShots << ".png";
		mWindow->writeContentsToFile(ss.str());
		mTimeUntilNextToggle = 250;
		mDebugText = "Saved: " + ss.str();
	}

	if(mKeyboard->isKeyDown(OIS::KC_R) && mTimeUntilNextToggle <=0)
	{
		restartRace = true;
	}

	if(mKeyboard->isKeyDown(OIS::KC_P) && mTimeUntilNextToggle <=0)
	{
		mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;
		switch(mSceneDetailIndex) {
		case 0 : 
			m_Cameras[0]->setPolygonMode(PM_SOLID);
			m_Cameras[1]->setPolygonMode(PM_SOLID);
			break;
		case 1 : 
			m_Cameras[0]->setPolygonMode(PM_WIREFRAME); 
			m_Cameras[1]->setPolygonMode(PM_WIREFRAME); 
			break;
		case 2 : 
			m_Cameras[0]->setPolygonMode(PM_POINTS); 
			m_Cameras[1]->setPolygonMode(PM_POINTS); 
			break;
		}
		mTimeUntilNextToggle = 250;
	}

	static bool displayCameraDetails = false;
	if(mKeyboard->isKeyDown(OIS::KC_O) && mTimeUntilNextToggle <= 0)
	{
		displayCameraDetails = !displayCameraDetails;
		mTimeUntilNextToggle = 250;
		if (!displayCameraDetails)
			mDebugText = "";
	}

	// Print camera details
	if(displayCameraDetails)
		mDebugText = "P: " + StringConverter::toString(m_Cameras[0]->getDerivedPosition()) +
		" " + "O: " + StringConverter::toString(m_Cameras[0]->getDerivedOrientation());

	// create and throw a box if 'B' is pressed
	if(mKeyboard->isKeyDown(OIS::KC_B) && mTimeUntilNextToggle <=0)
	{
		Vector3 size = Vector3::ZERO;	// size of the box
		// starting position of the box
		Vector3 position = (m_Cameras[0]->getDerivedPosition() + m_Cameras[0]->getDerivedDirection().normalisedCopy() * 10);

		// create an ordinary, Ogre mesh with texture
		Entity *entity = mSceneMgr->createEntity("Box" + StringConverter::toString(mNumEntitiesInstanced), "cube.mesh");
		entity->setCastShadows(true);
		// we need the bounding box of the box to be able to set the size of the Bullet-box
		AxisAlignedBox boundingB = entity->getBoundingBox();
		size = boundingB.getSize(); size /= 2.0f; // only the half needed
		size *= 0.95f;	// Bullet margin is a bit bigger so we need a smaller size
		// (Bullet 2.76 Physics SDK Manual page 18)
		entity->setMaterialName("Examples/BumpyMetal");
		SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		node->attachObject(entity);
		node->scale(0.05f, 0.05f, 0.05f);	// the cube is too big for us
		size *= 0.05f;						// don't forget to scale down the Bullet-box too

		// after that create the Bullet shape with the calculated size
		OgreBulletCollisions::BoxCollisionShape *sceneBoxShape = new OgreBulletCollisions::BoxCollisionShape(size);
		// and the Bullet rigid body
		OgreBulletDynamics::RigidBody *defaultBody = new OgreBulletDynamics::RigidBody(
			"defaultBoxRigid" + StringConverter::toString(mNumEntitiesInstanced), 
			mWorld);
		defaultBody->setShape(	node,
			sceneBoxShape,
			0.6f,			// dynamic body restitution
			0.6f,			// dynamic body friction
			0.3f,
			1.0f, 			// dynamic bodymass
			position,		// starting position of the box
			Quaternion(0,0,0,1));// orientation of the box
		mNumEntitiesInstanced++;				

		defaultBody->setLinearVelocity(m_Cameras[0]->getDerivedDirection().normalisedCopy() * 7.0f ); // shooting speed
		// push the created objects to the dequese
		mShapes.push_back(sceneBoxShape);
		mBodies.push_back(defaultBody);				
		mTimeUntilNextToggle = 250;
	}

	//Toggle keyboard controls
	if(mKeyboard->isKeyDown(OIS::KC_C) && mTimeUntilNextToggle <= 0)
	{
		mPlayer->toggleKbSteering();
		mTimeUntilNextToggle = 250;
	}

	if(mGameState == RACING)
	{
		mPlayer->steerKart(mKeyboard);
	}

	mKeyboard->copyKeyStates(mPrevKeys); //Save a copy of the current keys into the previous keys. 

	// Return true to continue rendering
	return true;
}

bool Oculus_KartVRFrameListener::processUnbufferedMouseInput(const FrameEvent& evt)
{
	// Rotation factors, may not be used if the second mouse button is pressed
	// 2nd mouse button - slide, otherwise rotate
	const OIS::MouseState &ms = mMouse->getMouseState();
	if( ms.buttonDown( OIS::MB_Right ) )
	{
		mTranslateVector.x += ms.X.rel * 0.13;
		mTranslateVector.y -= ms.Y.rel * 0.13;
	}
	else
	{
		mRotX = Degree(-ms.X.rel * 0.13);
		mRotY = Degree(-ms.Y.rel * 0.13);
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
		// Adjust the input depending upon viewport orientation
		Radian origRotY, origRotX;
		switch(m_Cameras->getViewport()->getOrientation())
		{
		case Viewport::OR_LANDSCAPELEFT:
			origRotY = mRotY;
			origRotX = mRotX;
			mRotX = origRotY;
			mRotY = -origRotX;
			break;
		case Viewport::OR_LANDSCAPERIGHT:
			origRotY = mRotY;
			origRotX = mRotX;
			mRotX = -origRotY;
			mRotY = origRotX;
			break;

			// Portrait doesn't need any change
		case Viewport::OR_PORTRAIT:
		default:
			break;
		}
#endif
	}

	return true;
}

bool Oculus_KartVRFrameListener::axisMoved(const OIS::JoyStickEvent &e, int axis)
{
	int x = e.state.mAxes[axis].abs;
	switch(axis)
	{
	//For Xbox controller
	//Y axis on Left Joystick. Up = Negative value, Down = Positive value
	case 0:
		break;
	//For Xbox controller
	//X axis on Left Joystick. Left = Negative value, Right = Positive value
	case 1:
		if(mGameState == RACING)
		{
			mPlayer->steerKart((float)x/mJoy->MAX_AXIS * -1);
		}
		
		break;
	//For Xbox controller
	//Y axis on Right Joystick. Up = Negative value, Down = Positive value
	case 2:
		break;
	//For Xbox controller
	//X axis on Right Joystick. Left = Negative value, Right = Positive value
	case 3:
		break;
	//For Xbox controller
	//Both triggers. LT = Positive value, RT = Negative value. If both triggers are pressed then value = zero.
	case 4:
		if(mGameState == RACING)
		{
			mPlayer->accelerateOrBrake((float)x/mJoy->MAX_AXIS * -1);
		}
		
		break;
	}

	return true;
}

bool Oculus_KartVRFrameListener::buttonPressed(const OIS::JoyStickEvent &e, int button)
{
	/* //Debugging multiple joystick inputs (controller/wheel).
	int asdf = mJoy->getID();
	OIS::Type fhdjs = mJoy->type();
	std::string hurhcg = mJoy->vendor();
	*/
	switch(button)
	{
	case 0: //Xbox A
		break;
	case 1: //Xbox B
		break;
	case 2: //Xbox X
		break;
	case 3: //Xbox Y
		break;
	case 4: //Xbox LB
		break;
	case 5: //Xbox RB
		break;
	case 6: //Xbox Back
		break;
	case 7: //Xbox Start
		break;
	case 8: //Xbox LS
		break;
	case 9: //Xbox RS
		break;
	}

	return true;
}

bool Oculus_KartVRFrameListener::buttonReleased(const OIS::JoyStickEvent &e, int button)
{
	switch(button)
	{
	case 0: //Xbox A
		break;
	case 1: //Xbox B
		break;
	case 2: //Xbox X
		break;
	case 3: //Xbox Y
		break;
	case 4: //Xbox LB
		break;
	case 5: //Xbox RB
		break;
	case 6: //Xbox Back
		break;
	case 7: //Xbox Start
		break;
	case 8: //Xbox LS
		break;
	case 9: //Xbox RS
		break;
	}

	return true;
}

bool Oculus_KartVRFrameListener::povMoved(const OIS::JoyStickEvent &e, int pov)
{
	
	return true;
};

void Oculus_KartVRFrameListener::moveCamera()
{
	for(int i=0;i<2;++i)
	{
		if(freeCam)
		{
			m_Cameras[i]->yaw(mRotX);
			m_Cameras[i]->pitch(mRotY);
			m_Cameras[i]->moveRelative(mTranslateVector);
		} else
		{
			m_Cameras[i]->setOrientation(mPlayer->getOrientation());
			m_Cameras[i]->yaw(Degree(180)); //For some reason the orientation of the player is backwards.
			Quaternion q = m_Cameras[i]->getOrientation();
			m_Cameras[i]->setOrientation(q * mORM->getOrientation());
			m_Cameras[i]->setPosition(mPlayer->getDriverPosition() + ((i * 2 - 1) * mORM->getStereoConfig()->GetIPD() * 0.5f, 0, 0));
		}
	}
	if(mCountDownPanel->isVisible)
	{
		Matrix3 countDownPosMtrx;
		Quaternion camOri = m_Cameras[0]->getOrientation();
		camOri.ToRotationMatrix(countDownPosMtrx);
		Vector3 cdDir = countDownPosMtrx.GetColumn(2);
		cdDir.normalise();
		cdDir *= -3.5f;
		cdDir += m_Cameras[0]->getPosition();
		mCountDownPanel->mD3PanelNode->_setDerivedPosition(cdDir);
		mCountDownPanel->mD3PanelNode->setOrientation(camOri);
	}
	if(mSpeedPanel->isVisible)
	{
		Quaternion camOri2 = m_Cameras[0]->getOrientation();
		Vector3 xAxis = camOri2 * Vector3::UNIT_X;
		Quaternion q;
		q.FromAngleAxis(Degree(-25),xAxis);
		q.normalise();
		q = q * camOri2;
		Matrix3 speedPosMtrx;
		q.ToRotationMatrix(speedPosMtrx);
		Vector3 speedDir = speedPosMtrx.GetColumn(2);
		speedDir.normalise();
		speedDir *= -3.5f;
		speedDir += m_Cameras[0]->getPosition();
		mSpeedPanel->mD3PanelNode->setOrientation(m_Cameras[0]->getOrientation());
		mSpeedPanel->mD3PanelNode->_setDerivedPosition(speedDir);
		mSpeedCaption->text(StringConverter::toString((int)mPlayer->getVelocity()) + " Km/h");
	}
	if(mTimerPanel->isVisible)
	{
		Quaternion camOri3 = m_Cameras[0]->getOrientation();
		Vector3 xAxis2 = camOri3 * Vector3::UNIT_X;
		Quaternion q2;
		q2.FromAngleAxis(Degree(20),xAxis2);
		q2.normalise();
		q2 = q2 * camOri3;
		Matrix3 TimerMtrx;
		q2.ToRotationMatrix(TimerMtrx);
		Vector3 timerDir = TimerMtrx.GetColumn(2);
		timerDir.normalise();
		timerDir *= -3.5f;
		timerDir += m_Cameras[0]->getPosition();
		mTimerPanel->mD3PanelNode->setOrientation(m_Cameras[0]->getOrientation());
		mTimerPanel->mD3PanelNode->_setDerivedPosition(timerDir);
		int min = 0;
		int sec = 0;
		int mil = 0;
		if(mPlayer->shouldDisplayPrevLapTime())
		{
			Real prevLapTime = mPlayer->getPrevLapTime();
			min = (int)prevLapTime / 60000;
			sec = ((int)prevLapTime % 60000) / 1000;
			mil = prevLapTime - ((min * 60000) + (sec * 1000));
		}
		else
		{
			min = (int)mRaceTime / 60000;
			sec = ((int)mRaceTime % 60000) / 1000;
			mil = mRaceTime - ((min * 60000) + (sec * 1000));
		}
		if(sec < 10)
		{
			if (mil == 0)
			{
				mTimerCaption->text(StringConverter::toString(min) + ":0" + StringConverter::toString(sec) + ".000");
			}
			else if(mil < 10)
			{
				mTimerCaption->text(StringConverter::toString(min) + ":0" + StringConverter::toString(sec) +
					".00" + StringConverter::toString(mil));
			}
			else if(mil < 100)
			{
				mTimerCaption->text(StringConverter::toString(min) + ":0" + StringConverter::toString(sec) +
					".0" + StringConverter::toString(mil));
			}
			else
			{
				mTimerCaption->text(StringConverter::toString(min) + ":0" + StringConverter::toString(sec) +
					"." + StringConverter::toString(mil));
			}
		} else
		{
			if (mil == 0)
			{
				mTimerCaption->text(StringConverter::toString(min) + ":" + StringConverter::toString(sec) + ".000");
			}
			else if(mil < 10)
			{
				mTimerCaption->text(StringConverter::toString(min) + ":" + StringConverter::toString(sec) +
					".00" + StringConverter::toString(mil));
			}
			else if(mil < 100)
			{
				mTimerCaption->text(StringConverter::toString(min) + ":" + StringConverter::toString(sec) +
					".0" + StringConverter::toString(mil));
			}
			else
			{
				mTimerCaption->text(StringConverter::toString(min) + ":" + StringConverter::toString(sec) +
					"." + StringConverter::toString(mil));
			}
		}
	}
	if(mPositionPanel->isVisible)
	{
		Quaternion camOri4 = m_Cameras[0]->getOrientation();
		Vector3 yAxis = camOri4 * Vector3::UNIT_Y;
		Quaternion q3;
		q3.FromAngleAxis(Degree(25),yAxis);
		q3.normalise();
		q3 = q3 * camOri4;
		Matrix3 PosMtrx;
		q3.ToRotationMatrix(PosMtrx);
		Vector3 posDir = PosMtrx.GetColumn(2);
		posDir.normalise();
		posDir *= -3.5f;
		posDir += m_Cameras[0]->getPosition();
		mPositionPanel->mD3PanelNode->setOrientation(m_Cameras[0]->getOrientation());
		mPositionPanel->mD3PanelNode->_setDerivedPosition(posDir);
		int pPos = mAI_Manager->calculatePlayerPosition(mPlayer);
		int numPos = mAI_Manager->numAgents()+1;
		if(pPos < 10)
		{
			if(numPos < 10)
			{
				mPositionCaption->text("0" + StringConverter::toString(pPos) + "/0" + StringConverter::toString(numPos));
			}
			else
			{
				mPositionCaption->text("0" + StringConverter::toString(pPos) + "/" + StringConverter::toString(numPos));
			}
		}
		else
		{
			if(numPos < 10)
			{
				mPositionCaption->text(StringConverter::toString(pPos) + "/0" + StringConverter::toString(numPos));
			}
			else
			{
				mPositionCaption->text(StringConverter::toString(pPos) + "/" + StringConverter::toString(numPos));
			}
		}
	}
	if(mLapPanel->isVisible)
	{
		Quaternion camOri5 = m_Cameras[0]->getOrientation();
		Vector3 yAxis2 = camOri5 * Vector3::UNIT_Y;
		Quaternion q4;
		q4.FromAngleAxis(Degree(-25),yAxis2);
		q4.normalise();
		q4 = q4 * camOri5;
		Matrix3 lapMtrx;
		q4.ToRotationMatrix(lapMtrx);
		Vector3 lapDir = lapMtrx.GetColumn(2);
		lapDir.normalise();
		lapDir *= -3.5f;
		lapDir += m_Cameras[0]->getPosition();
		mLapPanel->mD3PanelNode->setOrientation(m_Cameras[0]->getOrientation());
		mLapPanel->mD3PanelNode->_setDerivedPosition(lapDir);
		mLapCaption->text("L" + StringConverter::toString(mPlayer->getCurrentLap()) + "/" +
						  StringConverter::toString(mNumLaps));
	}
	if(mRaceEndPanel->isVisible)
	{
		Matrix3 raceEndPosMtrx;
		Quaternion camOri5 = m_Cameras[0]->getOrientation();
		camOri5.ToRotationMatrix(raceEndPosMtrx);
		Vector3 reDir = raceEndPosMtrx.GetColumn(2);
		reDir.normalise();
		reDir *= -3.5f;
		reDir += m_Cameras[0]->getPosition();
		mRaceEndPanel->mD3PanelNode->_setDerivedPosition(reDir);
		mRaceEndPanel->mD3PanelNode->setOrientation(camOri5);
		
		int pPos = mAI_Manager->calculatePlayerPosition(mPlayer);
		int numPos = mAI_Manager->numAgents()+1;
		if(pPos < 10)
		{
			if(numPos < 10)
			{
				mRaceEndPosCap->text("Pos: 0" + StringConverter::toString(pPos) + "/0" + StringConverter::toString(numPos));
			}
			else
			{
				mRaceEndPosCap->text("Pos: 0" + StringConverter::toString(pPos) + "/" + StringConverter::toString(numPos));
			}
		}
		else
		{
			if(numPos < 10)
			{
				mRaceEndPosCap->text("Pos: " + StringConverter::toString(pPos) + "/0" + StringConverter::toString(numPos));
			}
			else
			{
				mRaceEndPosCap->text("Pos: " + StringConverter::toString(pPos) + "/" + StringConverter::toString(numPos));
			}
		}

		Real bestLapTime = mPlayer->getBestLapTime();
		int min2 = (int)bestLapTime / 60000;
		int sec2 = ((int)bestLapTime % 60000) / 1000;
		int mil2 = bestLapTime - ((min2 * 60000) + (sec2 * 1000));
		if(sec2 < 10)
		{
			if (mil2 == 0)
			{
				mRaceEndBestLapCap->text("Best lap: " + StringConverter::toString(min2) + ":0" + StringConverter::toString(sec2) + ".000");
			}
			else if(mil2 < 10)
			{
				mRaceEndBestLapCap->text("Best lap: " + StringConverter::toString(min2) + ":0" + StringConverter::toString(sec2) +
					".00" + StringConverter::toString(mil2));
			}
			else if(mil2 < 100)
			{
				mRaceEndBestLapCap->text("Best lap: " + StringConverter::toString(min2) + ":0" + StringConverter::toString(sec2) +
					".0" + StringConverter::toString(mil2));
			}
			else
			{
				mRaceEndBestLapCap->text("Best lap: " + StringConverter::toString(min2) + ":0" + StringConverter::toString(sec2) +
					"." + StringConverter::toString(mil2));
			}
		} else
		{
			if (mil2 == 0)
			{
				mRaceEndBestLapCap->text("Best lap: " + StringConverter::toString(min2) + ":" + StringConverter::toString(sec2) + ".000");
			}
			else if(mil2 < 10)
			{
				mRaceEndBestLapCap->text("Best lap: " + StringConverter::toString(min2) + ":" + StringConverter::toString(sec2) +
					".00" + StringConverter::toString(mil2));
			}
			else if(mil2 < 100)
			{
				mRaceEndBestLapCap->text("Best lap: " + StringConverter::toString(min2) + ":" + StringConverter::toString(sec2) +
					".0" + StringConverter::toString(mil2));
			}
			else
			{
				mRaceEndBestLapCap->text("Best lap: " + StringConverter::toString(min2) + ":" + StringConverter::toString(sec2) +
					"." + StringConverter::toString(mil2));
			}
		}
	}
}

void Oculus_KartVRFrameListener::showDebugOverlay(bool show)
{
	if (mDebugOverlay)
	{
		if (show)
			mDebugOverlay->show();
		else
			mDebugOverlay->hide();
	}
}

bool Oculus_KartVRFrameListener::frameStarted(const FrameEvent& evt)
{
	mPlayer->update(evt.timeSinceLastFrame, mGameState);
	mAI_Manager->update(evt.timeSinceLastFrame, mGameState);
	mWorld->stepSimulation(evt.timeSinceLastFrame);	// update Bullet Physics animation
	headNode->setPosition((m_Cameras[0]->getPosition() + m_Cameras[1]->getPosition()) / 2);
	headNode->setOrientation(m_Cameras[0]->getOrientation());
	mSoundManager->getSound("Engine_Rev")->setPitch(0.65f + (mPlayer->getVelocity() / 115)*0.85f);
	mSoundManager->update(evt.timeSinceLastFrame);
	bool ret = FrameListener::frameStarted(evt);
	return ret;
}

bool Oculus_KartVRFrameListener::frameRenderingQueued(const FrameEvent& evt)
{

	if(mWindow->isClosed())	return false;

	mSpeedLimit = mMoveScale * evt.timeSinceLastFrame/1000; //converting from microseconds to milliseconds

	//Need to capture/update each device
	mKeyboard->capture();
	mMouse->capture();
	if( mJoy ) mJoy->capture();

	bool buffJ = (mJoy) ? mJoy->buffered() : true;

	Ogre::Vector3 lastMotion = mTranslateVector;

	//Check if one of the devices is not buffered
	if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )
	{
		// one of the input modes is immediate, so setup what is needed for immediate movement
		if (mTimeUntilNextToggle >= 0)
			mTimeUntilNextToggle -= evt.timeSinceLastFrame/1000; //converting from microseconds to milliseconds

		// Move about 100 units per second
		mMoveScale = mMoveSpeed * evt.timeSinceLastFrame/1000;
		// Take about 10 seconds for full rotation
		mRotScale = mRotateSpeed * evt.timeSinceLastFrame/1000;

		mRotX = 0;
		mRotY = 0;
		mTranslateVector = Ogre::Vector3::ZERO;

	}

	//Check to see which device is not buffered, and handle it
#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
	if( !mKeyboard->buffered() )
		if( processUnbufferedKeyInput(evt) == false )
			return false;

#ifdef USE_RTSHADER_SYSTEM
	processShaderGeneratorInput();
#endif

#endif
	if( !mMouse->buffered() )
		if( processUnbufferedMouseInput(evt) == false )
			return false;

	// ramp up / ramp down speed
	if (mTranslateVector == Ogre::Vector3::ZERO)
	{
		// decay (one third speed)
		mCurrentSpeed -= evt.timeSinceLastFrame * 0.3 / 1000;
		mTranslateVector = lastMotion;
	}
	else
	{
		// ramp up
		mCurrentSpeed += evt.timeSinceLastFrame/1000;

	}
	// Limit motion speed
	if (mCurrentSpeed > 1.0)
		mCurrentSpeed = 1.0;
	if (mCurrentSpeed < 0.0)
		mCurrentSpeed = 0.0;

	mTranslateVector *= mCurrentSpeed;


	if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )
		moveCamera();

	mTimeSinceLastGameStateChange += evt.timeSinceLastFrame/1000; //converting from microseconds to milliseconds

	if (mGameState == LOADING)
	{
		if (mTimeSinceLastGameStateChange > 5000)
		{
			changeGameState(COUNTDOWN);
			mSoundManager->getSound("BGM")->play();
			mSoundManager->getSound("Beep")->play();
			mSoundManager->getSound("Engine_Rev")->play();
		}
	}

	if (mGameState == COUNTDOWN)
	{
		mCountDownPanel->setVisible(true);
		mCountDown -= evt.timeSinceLastFrame/1000;
		mBeepCooldown -= evt.timeSinceLastFrame/1000;
		if(((mCountDown < 4015) && (mCountDown > 3985) && (mBeepCooldown <=0)) ||
		   ((mCountDown < 3015) && (mCountDown > 2985) && (mBeepCooldown <=0)) ||
		   ((mCountDown < 2015) && (mCountDown > 1985) && (mBeepCooldown <=0)) ||
		   ((mCountDown < 1015) && (mCountDown > 985) && (mBeepCooldown <=0)))
		{
			mBeepCooldown = 980;
			mSoundManager->getSound("Beep")->play();
		} else if((mCountDown < 15) && (mCountDown > -15) && (mBeepCooldown <=0))
		{
			mBeepCooldown = 980;
			mSoundManager->getSound("FinalBeep")->play();
		}
		if (mCountDown <= 0)
		{
			mCountDownCaption->text("GO!!!");
			changeGameState(RACING);
			mRaceTime = 0;
			mCountDown = 5000;
			mBeepCooldown = 980;
		} else
		{
			mCountDownCaption->text(StringConverter::toString(((int)mCountDown/1000)+1));
		}
	} else
	{
		if (mGameState == RACING)
		{
			if (mTimeSinceLastGameStateChange > 1000)
			{
				mCountDownPanel->setVisible(false);
			}
		}
	}

	if (mGameState == RACING)
	{
		mRaceTime += evt.timeSinceLastFrame / 1000;
		if(mPlayer->getCurrentLap() >= 2)
		{
			if(mPlayer->shouldDisplayPrevLapTime())
			{
				mShowLastLapTime -= evt.timeSinceLastFrame/1000;
				if(mShowLastLapTime < 0)
				{
					mPlayer->resetPrevLapTimeDisplay();
				}
			}
			else
			{
				mShowLastLapTime = 5000;
			}
			if(mPlayer->getCurrentLap() > 5)
			{
				changeGameState(RACEEND);
				mPlayer->toggleKbSteering();
				mPlayer->accelerateOrBrake(0.0f);
				freeCam = !freeCam;
				mPositionPanel->setVisible(false);
				mLapPanel->setVisible(false);
				mSpeedPanel->setVisible(false);
				mPlayer->resetPrevLapTimeDisplay();
				mRaceEndPanel->setVisible(true);
			}
		}
	}
	return true;
}

bool Oculus_KartVRFrameListener::frameEnded(const FrameEvent& evt)
{
	updateStats();
	bool ret = FrameListener::frameEnded(evt);
	return ret;
}

void Oculus_KartVRFrameListener::changeGameState(GameState state)
{
	mTimeSinceLastGameStateChange = 0;
	mGameState = state;
}

void Oculus_KartVRFrameListener::updateStats(void)
{
	static String currFps = "Current FPS: ";
	static String avgFps = "Average FPS: ";
	static String bestFps = "Best FPS: ";
	static String worstFps = "Worst FPS: ";
	static String tris = "Triangle Count: ";
	static String batches = "Batch Count: ";

	// update stats when necessary
	try {
		OverlayElement *guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
		OverlayElement *guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
		OverlayElement *guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
		OverlayElement *guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");

		const RenderTarget::FrameStats& stats = mWindow->getStatistics();
		guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
		guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));
		guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
			+" "+StringConverter::toString(stats.bestFrameTime)+" ms");
		guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
			+" "+StringConverter::toString(stats.worstFrameTime)+" ms");

		OverlayElement *guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
		guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));

		OverlayElement *guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches");
		guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount));

		OverlayElement *guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
		guiDbg->setCaption(mDebugText);
	}
	catch(...) { /* ignore */ }
}